package com.xcity.game.peakroad.model;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.annotation.JSONField;
import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Player;
import com.xcity.game.combat.attr.CombatAttribute;
import com.xcity.game.combat.attr.CombatAttributeType;
import com.xcity.game.combat.unit.Combatable;
import com.xcity.game.formation.Formation;
import com.xcity.game.peakroad.PeakRoadUtils;
import com.xcity.game.peakroad.combat.PeakRoadCombatable;
import com.xcity.game.peakroad.template.PeakRoadTemplate;
import com.xcity.pomelo.push.SyncPush;
import com.xcity.pomelo.push.sync.MapSync;

import naga.x.game.GameUnit;
import naga.x.game.time.TimeUpdater;

public class PeakRoadInstance {

	@JSONField(name = "0")
	protected int lastChallengeDay; // 上一次挑战日期
	@JSONField(name = "1")
	protected int lastMaxFloor; // 上一次挑战到的最高层数
	@JSONField(name = "2")
	protected int floor; // 当前所处层数
	@JSONField(name = "3")
	protected List<CombatAttribute> buffs; // 上一次累计获得的buff
	@JSONField(name = "4")
	protected List<PeakRoadCombatable> units; // 己方战斗过的单位
	@JSONField(name = "5")
	protected List<PeakRoadCombatable> lastNpcUnits; // 上一次挑战的npc战斗单位，最后一个为boss（仅战斗失败时记录）
	@JSONField(name = "6")
	protected int state; // 所在层状态
	@JSONField(name = "7")
	protected int joinedTimes; // 今日已挑战次数
	@JSONField(name = "8")
	protected int lastChallengeDiff; // 上一次挑战的难度(0:简单,1:中等,2:困难)
	@JSONField(name = "9")
	protected int passedMaxHardFloor; // 历史达到的最高困难层数
	
	protected Player owner;
	
	public static final int STATE_CHALLENGE_MASK = 0x1; // 挑战层状态（0=失败，1=成功）
	public static final int STATE_REWARD_BUFF_MASK = 0x2; // 奖励层buff领取状态（0=未领，1=已领）
	public static final int STATE_REWARD_ITEM_MASK = 0x4; // 奖励层物品领取状态
	public static final int STATE_PREVIOUS_CHALLENGE_MASK = 0x8; // 上一次挑战状态（0=失败，1=成功）
	
	public PeakRoadInstance() {}
	
	public PeakRoadInstance(Player owner) {
		this.floor = 1;
		this.owner = owner;
	}
	
	@JSONField(serialize = false)
	public Player getOwner() {
		return owner;
	}
	
	public void setOwner(Player owner) {
		this.owner = owner;
	}
	
	public int getLastChallengeDay() {
		return lastChallengeDay;
	}

	public void setLastChallengeDay(int lastChallengeDay) {
		this.lastChallengeDay = lastChallengeDay;
	}

	public int getLastMaxFloor() {
		return lastMaxFloor;
	}

	public void setLastMaxFloor(int lastMaxFloor) {
		this.lastMaxFloor = lastMaxFloor;
	}

	public int getFloor() {
		return floor;
	}

	public void setFloor(int floor) {
		this.floor = floor;
	}

	public List<CombatAttribute> getBuffs() {
		return buffs;
	}

	public void setBuffs(List<CombatAttribute> buffs) {
		this.buffs = buffs;
	}

	public List<PeakRoadCombatable> getUnits() {
		return units;
	}

	public void setUnits(List<PeakRoadCombatable> units) {
		this.units = units;
	}

	public List<PeakRoadCombatable> getLastNpcUnits() {
		return lastNpcUnits;
	}

	public void setLastNpcUnits(List<PeakRoadCombatable> lastNpcUnits) {
		this.lastNpcUnits = lastNpcUnits;
	}

	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
	}
	
	public int getJoinedTimes() {
		return joinedTimes;
	}

	public void setJoinedTimes(int joinedTimes) {
		this.joinedTimes = joinedTimes;
	}
	
	public int getLastChallengeDiff() {
		return lastChallengeDiff;
	}

	public void setLastChallengeDiff(int lastChallengeDiff) {
		this.lastChallengeDiff = lastChallengeDiff;
	}

	public int getPassedMaxHardFloor() {
		return passedMaxHardFloor;
	}

	public void setPassedMaxHardFloor(int passedMaxHardFloor) {
		this.passedMaxHardFloor = passedMaxHardFloor;
	}

	public boolean isDied(GameUnit unit) {
		PeakRoadCombatable u = findUnit(unit);
		return u != null && u.getHp() <= 0;
	}
	
	@JSONField(serialize = false)
	public PeakRoadCombatable[] getFormationUnits() {
		Employee[] employees = owner.getFormations().get(Formation.TYPE_PEAK_ROAD).getUnits();
		PeakRoadCombatable[] arr = new PeakRoadCombatable[employees.length];
		for (int i = 0; i < employees.length; i++) {
			Employee e = employees[i];
			if (e != null) {
				PeakRoadCombatable u = findUnit(e);
				if (u != null && u.getHp() > 0) { // alive
					arr[i] = u;
				}
			}
		}
		return arr;
	}
	
	public PeakRoadCombatable findUnit(GameUnit refer) {
		for (int i = units != null ? units.size() - 1 : -1; i >= 0; i--) {
			PeakRoadCombatable c = units.get(i);
			if (c.getId() == refer.getId()) {
				return c;
			}
		}
		PeakRoadCombatable c = null;
		if (refer instanceof Player) {
			addUnit(c = new PeakRoadCombatable((Player) refer));
		} else if (refer instanceof Employee) {
			addUnit(c = new PeakRoadCombatable((Employee) refer));
		}/* else if (refer instanceof NpcCombatable) { // impossible
			addUnit(c = new PeakRoadCombatable((NpcCombatable) refer));
		}*/
		if (c != null) { // 加血buff生效
			CombatAttribute buff = getBuff(CombatAttributeType.HP);
			if (buff != null) {
				c.setHp((int) PeakRoadUtils.addBuff(c.getHp(), buff));
			}
		}
		return c;
	}
	
	public void addUnit(PeakRoadCombatable u) {
		if (units == null) {
			units = new ArrayList<PeakRoadCombatable>();
		}
		units.add(u);
	}
	
	public void addBuff(CombatAttribute buff, boolean save) {
		addState(STATE_REWARD_BUFF_MASK);
		if (buffs == null) {
			buffs = new ArrayList<CombatAttribute>();
		}
		// try merge the same buff
		CombatAttribute newBuff = getBuff(buff.getType());
		if (newBuff == null) {
			newBuff = new CombatAttribute(buff.getType(), buff.getValue()); // must new
			buffs.add(newBuff);
		} else if (buff.getValue() > newBuff.getValue()) {
			newBuff.setValue(buff.getValue());
		}
		if (newBuff.getType() == CombatAttributeType.HP && units != null) { // 加血buff立刻生效
			for (int i = 0; i < units.size(); i++) {
				PeakRoadCombatable u = units.get(i);
				if (u.getHp() > 0) {
					u.setHp((int) PeakRoadUtils.addBuff(u.getHp(), newBuff));
				}
			}
		}
	}
	
	public CombatAttribute getBuff(CombatAttributeType type) {
		if (buffs == null) {
			return null;
		}
		for (int i = buffs.size() - 1; i >= 0; i--) {
			CombatAttribute buff = buffs.get(i);
			if (buff.getType() == type) {
				return buff;
			}
		}
		return null;
	}
	
	public void addState(int mask) {
		state |= mask;
	}
	
	public void removeState(int mask) {
		state &= ~mask;
	}
	
	public boolean hasState(int mask) {
		return (state & mask) != 0;
	}
	
	public void init() {
		// try reset
		if (lastChallengeDay != TimeUpdater.getInstance().today()) {
			lastChallengeDay = TimeUpdater.getInstance().today();
			joinedTimes = 0;
			fireChallengeFailed(null);
//			if (owner.getVipLvl() < 5 || lastMaxFloor == 1) { // vip5以上不清除前一天的状态
				clear();
//			}
		}
		initUnits(units);
		if (!initUnits(lastNpcUnits)) {
			lastNpcUnits = null;
		}
		syncUnitsHp();
	}
	
	private boolean initUnits(List<PeakRoadCombatable> units) {
		boolean succ = true;
		if (units != null) {
			for (int i = units.size() - 1; i >= 0; i--) {
				PeakRoadCombatable c = units.get(i);
				c.init(this);
				if (c.refer() == null) { // not found (npc template removed)
					units.remove(i);
					GameUnit.LOG.info("[PEAKROAD UNIT REMOVED]ID[{}]UNIT[{}]TYPE[{}]", owner.getId(), c.getId(), c.getType());
					succ = false; // don't break
				}
			}
		}
		return succ;
	}
	
	public void clear() {
		lastMaxFloor = 1;
		buffs = null;
		lastChallengeDiff = 0;
	}
	
	public void enter(int diff) { // 进入战斗
		if (lastMaxFloor > floor || lastMaxFloor == 1) {
			clear();
		}
		lastChallengeDiff = diff;
	}
	
	public void fireChallengeSucceeded(PeakRoadTemplate template) {
		syncUnitsHp();
		lastMaxFloor = template.getId();
		addState(STATE_CHALLENGE_MASK);
		addState(STATE_PREVIOUS_CHALLENGE_MASK);
		moveToNext();
		if (lastChallengeDiff == PeakRoadTemplate.DIFF_HARD && lastMaxFloor > passedMaxHardFloor) {
			passedMaxHardFloor = lastMaxFloor;
		}
	}
	
	public void fireChallengeFailed(PeakRoadTemplate template) {
		syncUnitsNativeHp();
		floor = 1; // rollback to 1
		units = null;
		lastNpcUnits = null;
		state = 0; // clear all state
	}
	
	public boolean moveToNext() {
		if (floor < PeakRoadUtils.getTopFloor()) {
			PeakRoadTemplate next = PeakRoadUtils.getTemplate(++floor);
			if (next.getType() == PeakRoadTemplate.FLOOR_CHALLENGE) {
				removeState(STATE_CHALLENGE_MASK);
			} else {
				removeState(STATE_REWARD_BUFF_MASK);
				removeState(STATE_REWARD_ITEM_MASK);
			}
			lastMaxFloor = floor;
			return true;
		}
		return false;
	}
	
	public void fastPass() {
//		floor = lastMaxFloor;
//		removeState(STATE_CHALLENGE_MASK);
//		addState(STATE_REWARD_BUFF_MASK);
//		addState(STATE_REWARD_ITEM_MASK);
		floor = passedMaxHardFloor;
		addState(STATE_CHALLENGE_MASK);
		addState(STATE_REWARD_BUFF_MASK);
		addState(STATE_REWARD_ITEM_MASK);
		moveToNext();
	}
	
	public void syncUnitsHp() {
		syncUnitsHp(false);
	}
	
	public void syncUnitsNativeHp() {
		syncUnitsHp(true);
	}
	
	private void syncUnitsHp(boolean isNative) {
		if (units != null) {
			for (int i = units.size() - 1; i >= 0; i--) {
				PeakRoadCombatable c = units.get(i);
				if (c.refer() == null) { // not init yet
					continue;
				}
				if (c.getType() == Combatable.EMPLOYEE) {
					owner.send(new MapSync(SyncPush.SYNC_PEAK_ROAD_UNIT_HP, -1, isNative ? c.refer().getHp() : c.getHp()));
				} else if (c.getType() == Combatable.PLAYER) {
					owner.send(new MapSync(SyncPush.SYNC_PEAK_ROAD_UNIT_HP, c.getId(), isNative ? c.refer().getHp() : c.getHp()));
				}
			}
		}
	}
	
}
